package com.road.common.core;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

/**
 * 网关配置
 */
public class NetConfig {

	private static final Logger LOGGER = LoggerFactory.getLogger(NetConfig.class);

	public static int crossCount = 0;
	public static int gatewayCount = 0;
	public static String site = null;
	public static String crossNames = null;
	public static String timeZone = null;

	private static Map<Integer, NetConfigXml> gatewayMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> castleMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> battleMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> chatMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> crossMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> judgeMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> mainDBMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> logDBMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> webMap = new HashMap<Integer, NetConfigXml>();
	private static Map<Integer, NetConfigXml> chargeDBMap = new HashMap<Integer, NetConfigXml>();

	public static boolean init(String globalPath, String crossPath) {
		Preconditions.checkArgument(StringUtils.isNotBlank(globalPath) && StringUtils.isNotBlank(crossPath), "网关配置文件不能为空");

		if (!initGlobal(globalPath)) {
			LOGGER.error("Init global netconfig fail , globalPath : {}", globalPath);
			return false;
		}

		if (!initCross(crossPath)) {
			LOGGER.error("Init cross netconfig fail , crossPath : {}", crossPath);
			return false;
		}

		gatewayCount = gatewayMap.size();
		crossCount = crossMap.size();
		return true;
	}

	private static boolean initGlobal(String globalPath) {
		try {
			SAXReader reader = new SAXReader();
			Document doc = reader.read(globalPath);
			Element root = doc.getRootElement();

			Element castle = root.element("castle_server");
			init(castle, "castle", castleMap);
			Element battle = root.element("battle_server");
			init(battle, "battle", battleMap);
			Element chat = root.element("chat_server");
			init(chat, "chat", chatMap);
			Element gateway = root.element("gateway_server");
			init(gateway, "gateway", gatewayMap);
			Element judge = root.element("judge_server");
			init(judge, "judge", judgeMap);

			Element mainDb = root.element("maindb_server");
			init(mainDb, "db", mainDBMap);

			Element logDb = root.element("logdb_server");
			init(logDb, "db", logDBMap);

			Element web = root.element("web_server");
			init(web, "web", webMap);

			site = getSite();
			timeZone = root.attributeValue("cross_group");

			Element chargeDB = root.element("chargedb_server");
			init(chargeDB, "db", chargeDBMap);

			return true;
		} catch (Exception e) {
			LOGGER.error("init global config file fialed., server start failed.", e);
			return false;
		}
	}

	public static boolean initCross(String crossPath) {
		try {
			if (site == null || site.trim().length() == 0) {
				LOGGER.error("init cross config failure. cross group error.");
				return false;
			}
			if (null != crossMap && crossMap.size() > 0) {
				crossMap = new HashMap<Integer, NetConfigXml>();
			}
			if (timeZone == null || timeZone.trim().length() == 0) {
				LOGGER.error("init cross config failure. timeZone error.");
				return false;
			}

			SAXReader reader = new SAXReader();
			Document doc = reader.read(crossPath);
			Element root = doc.getRootElement();
			Iterator<?> groupItr = root.elementIterator();
			boolean isHaveCross = false;
			Element otherCross = null;
			while (groupItr.hasNext()) {
				Element temp = (Element) groupItr.next();
				if ("cross_server".equals(temp.getName())) {
					String group = temp.attributeValue("group");
					if (group == null || "".equals(group)) {
						continue;
					}
					String[] arrayStr = group.split(",");
					List<String> list = Arrays.asList(arrayStr);
					if (list.contains(site)) {
						init(temp, "cross", crossMap);
						isHaveCross = true;
						crossNames = temp.attributeValue("ordername");
						break;
					}

					if (group.equals(timeZone)) {
						otherCross = temp;
					}
				}
			}

			if (!isHaveCross) {
				if (otherCross == null) {
					System.err.println("未设置通用的跨服服务器,init cross config file failure");
					return false;
				}
				init(otherCross, "cross", crossMap);
				crossNames = otherCross.attributeValue("ordername");
			}
			return true;
		} catch (Exception e) {
			System.err.println("init cross config file failure, server start failure.");
			return false;
		}
	}

	private static void init(Element root, String nodeName, Map<Integer, NetConfigXml> map) {
		if (root == null) {
			return;
		}
		Iterator<?> itr = root.elementIterator(nodeName);
		while (itr.hasNext()) {
			Element element = (Element) itr.next();
			int id = Integer.valueOf(element.attributeValue("id"));
			String name = element.attributeValue("name");
			int port = Integer.valueOf(element.attributeValue("port"));
			int adminPort = 0;
			if (element.attributeValue("adminPort") != null) {
				adminPort = Integer.valueOf(element.attributeValue("adminPort"));
			}
			String address = element.attributeValue("address");
			String user = element.attributeValue("user");
			String password = element.attributeValue("password");
			String desc = element.attributeValue("desc");
			NetConfigXml configXml = new NetConfigXml(id, name, address, port, adminPort, user, password, desc);
			map.put(configXml.getId(), configXml);
			LOGGER.info("Loading server config succ, {}", configXml);
		}
	}

	/**
	 * 服务器配置
	 *
	 * @param serverType
	 * @param serverId
	 * @return
	 */
	public static NetConfigXml getNetConfigXml(int serverType, int serverId) {
		NetConfigXml xml = null;
		switch (serverType) {
		case ServerType.GATEWAY:
			xml = gatewayMap.get(serverId);
			break;
		case ServerType.CASTLE:
			xml = castleMap.get(serverId);
			break;
		case ServerType.BATTLE:
			xml = battleMap.get(serverId);
			break;
		case ServerType.CHAT:
			xml = chatMap.get(serverId);
			break;
		case ServerType.CROSS:
			xml = crossMap.get(serverId);
			break;
		case ServerType.JUDGE:
			xml = judgeMap.get(serverId);
			break;
		case ServerType.MAINDB:
			xml = mainDBMap.get(serverId);
			break;
		case ServerType.LOGDB:
			xml = logDBMap.get(serverId);
			break;
		case ServerType.WEB:
			xml = webMap.get(serverId);
			break;
		case ServerType.CHARGEDB:
			xml = chargeDBMap.get(serverId);
			break;
		}
		return xml;
	}

	/**
	 * 服务器配置
	 *
	 * @param serverType
	 * @param serverId
	 * @return
	 */
	public static Collection<NetConfigXml> getNetConfigXml(int serverType) {
		Collection<NetConfigXml> xml = null;
		switch (serverType) {
		case ServerType.GATEWAY:
			xml = gatewayMap.values();
			break;
		case ServerType.CASTLE:
			xml = castleMap.values();
			break;
		case ServerType.BATTLE:
			xml = battleMap.values();
			break;
		case ServerType.CHAT:
			xml = chatMap.values();
			break;
		case ServerType.CROSS:
			xml = crossMap.values();
			break;
		}
		return xml;
	}

	/**
	 * 网关连接数量
	 *
	 * @return
	 */
	public static int gatewayCount() {
		return gatewayCount;
	}

	public static int getCrossCount() {
		return crossCount;
	}

	public static String getWebSiteUrl() {
		NetConfigXml config = getNetConfigXml(ServerType.GATEWAY, 0);
		if (config != null) {
			return config.getAddress();
		}
		return "";
	}

	public static String getSite() {
		if (site == null) {
			NetConfigXml config = getNetConfigXml(ServerType.GATEWAY, 0);
			if (config != null) {
				site = config.getName();
			}
		}
		return site;
	}

	public static String getCrossName() {
		if (crossNames != null && crossNames.trim().length() > 0) {
			return crossNames;
		} else {
			return getSite();
		}
	}
}
